/* 判断一个元素是否在数组中 */
export function contains(arr, val) {
  return arr.indexOf(val) !== -1;
}

/**
 * @param  {arr} 数组
 * @param  {type} 1：从小到大   2：从大到小   3：随机
 * @return {Array}
 */
export function sort(arr, type = 1) {
  return arr.sort((a, b) => {
    switch (type) {
      case 1:
        return a - b;
      case 2:
        return b - a;
      case 3:
        return Math.random() - 0.5;
      default:
        return arr;
    }
  });
}
/**
 * 从数组中按照下标删除元素
 * @indexArray  {[array]} 需要删除的数组下标
 * @array  {[array]} 需要删除元素的数组
 * @return {[type]}
 */
export function deleteArrayFromArray(indexArray, array) {
  array = array.concat();
  const newIndexs = indexArray.map((val, idx) => val - idx);
  newIndexs.forEach(index => {
    array.splice(index, 1);
  });
  return array;
}
/* 去重 */
export function unique(arr) {
  // eslint-disable-next-line no-prototype-builtins
  if (arr.hasOwnProperty("from")) {
    return Array.from(new Set(arr));
  }
  const n = {};
  const r = [];
  for (let i = 0; i < arr.length; i++) {
    if (!n[arr[i]]) {
      n[arr[i]] = true;
      r.push(arr[i]);
    }
  }
  return r;

  // 注：上面 else 里面的排重并不能区分 2 和 '2'，但能减少用indexOf带来的性能
  /* 正确排重
  if ( Array.hasOwnProperty('from') ) {
      return Array.from(new Set(arr))
  }else{
      var r = [], NaNBol = true
      for(var i=0; i < arr.length; i++) {
          if (arr[i] !== arr[i]) {
              if (NaNBol && r.indexOf(arr[i]) === -1) {
                  r.push(arr[i])
                  NaNBol = false
              }
          }else{
              if(r.indexOf(arr[i]) === -1) r.push(arr[i])
          }
      }
      return r
  }
    */
}

/* 求两个集合的并集 */
export function union(a, b) {
  const newArr = a.concat(b);
  return this.unique(newArr);
}

/* 求两个集合的交集 */
export function intersect(a, b) {
  a = this.unique(a);
  return this.map(a, o => (this.contains(b, o) ? o : null));
}

/* 删除其中一个元素 */
export function remove(arr, ele) {
  const index = arr.indexOf(ele);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}

/* 将类数组转换为数组的方法 */
export function formArray(ary) {
  let arr = [];
  if (Array.isArray(ary)) {
    arr = ary;
  } else {
    arr = Array.prototype.slice.call(ary);
  }
  return arr;
}

/* 最大值 */
export function max(arr) {
  return Math.max.apply(null, arr);
}

/* 最小值 */
export function min(arr) {
  return Math.min.apply(null, arr);
}

/* 求和 */
export function sum(arr) {
  return arr.reduce((pre, cur) => pre + cur);
}

/* 数组filter（搜索功能） */

export function filterItems(arr, query) {
  return arr.filter(
    item => item.toLowerCase().indexOf(query.toLowerCase()) > -1
  );
}
// var fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];
// console.log(filterItems('ap')); // ['apple', 'grapes']

export function isRepeat(arr) {
  const hash = {};
  for (const i of arr) {
    if (hash[arr[i]]) {
      return true;
    }
    hash[arr[i]] = true;
  }
  return false;
}

// 将一个数组按指定长度分割，组成一个新的数组集合
export function chunk(array, size) {
  // 获取数组的长度，如果你传入的不是数组，那么获取到的就是undefined
  const { length } = array;
  // 判断不是数组，或者size没有设置，size小于1，就返回空数组
  if (!length || !size || size < 1) {
    return [];
  }
  // 核心部分
  let index = 0; // 用来表示切割元素的范围start
  let resIndex = 0; // 用来递增表示输出数组的下标

  // 根据length和size算出输出数组的长度，并且创建它。
  const result = new Array(Math.ceil(length / size));
  // 进行循环
  while (index < length) {
    // 循环过程中设置result[0]和result[1]的值。该值根据array.slice切割得到。
    result[resIndex++] = array.slice(index, (index += size));
  }
  // 输出新数组
  return result;
}
// `arrayToCSV`：数组转`CSV`格式（带空格的字符串）
// arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"'
export const arrayToCSV = (arr, delimiter = ",") =>
  arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join("\n");
//  `average`：平均数
// average(...[1, 2, 3]); // 2
export const average = (...nums) =>
  nums.reduce((acc, val) => acc + val, 0) / nums.length;

// countOccurrences`：检测数值出现次数
// countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
export const countOccurrences = (arr, val) =>
  arr.reduce((a, v) => (v === val ? a + 1 : a), 0);

// deepFlatten`：递归扁平化数组
// deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
export const deepFlatten = arr =>
  [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));

// 16. `flatten`：指定深度扁平化数组
// flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
// flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
export const flatten = (arr, depth = 1) =>
  arr.reduce(
    (a, v) =>
      a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v),
    []
  );

// `indexOfAll`：返回数组中某值的所有索引
// indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
// indexOfAll([1, 2, 3], 4); // []
export const indexOfAll = (arr, val) =>
  arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);

//  `randomIntArrayInRange`：生成两数之间指定长度的随机数组
// randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ]
// eslint-disable-next-line no-shadow
export const randomIntArrayInRange = (min, max, n = 1) =>
  Array.from(
    { length: n },
    () => Math.floor(Math.random() * (max - min + 1)) + min
  );

// `sampleSize`：在指定数组中获取指定长度的随机数
// 此代码段可用于从数组中获取指定长度的随机数，直至穷尽数组。
// 使用Fisher - Yates算法对数组中的元素进行随机选择。
// sampleSize([1, 2, 3], 2); // [3,1]
// sampleSize([1, 2, 3], 4); // [2,3,1]
export const sampleSize = ([...arr], n = 1) => {
  let m = arr.length;
  while (m) {
    const i = Math.floor(Math.random() * m--);
    [arr[m], arr[i]] = [arr[i], arr[m]];
  }
  return arr.slice(0, n);
};
// . `shuffle`：“洗牌” 数组
// 此代码段使用Fisher-Yates算法随机排序数组的元素
// const foo = [1, 2, 3];
// shuffle(foo); // [2, 3, 1], foo = [1, 2, 3]
export const shuffle = ([...arr]) => {
  let m = arr.length;
  while (m) {
    const i = Math.floor(Math.random() * m--);
    [arr[m], arr[i]] = [arr[i], arr[m]];
  }
  return arr;
};

//  `nest`：根据`parent_id`生成树结构（阿里一面真题）
// 根据每项的parent_id，生成具体树形结构的对象。
// const comments = [
//   { id: 1, parent_id: null },
//   { id: 2, parent_id: 1 },
//   { id: 3, parent_id: 1 },
//   { id: 4, parent_id: 2 },
//   { id: 5, parent_id: 4 }
// ];
// const nestedComments = nest(comments); // [{ id: 1, parent_id: null, children: [...] }]
export const nest = (items, id = null, link = "parent_id") =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }));
